package com.lagou.edu.context;

import com.lagou.edu.annotation.*;
import com.lagou.edu.factory.ProxyFactory;
import com.lagou.edu.utils.ClassUtil;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


/**
 * IOC容器
 */
public class KevinApplicationContext {

    private static String packageName;

    public KevinApplicationContext(String packageName) {
        this.packageName = packageName;
    }

    //存放所有的bean
    public static final Map<Class<?>, Object> beans = new ConcurrentHashMap<Class<?>, Object>();

    /**
     * 扫描指定包
     * @throws IOException
     */
    public static Map<Class<?>, Object> initBean() throws Exception {
        //获取指定包下所有的class类
        List<Class<?>> classes= ClassUtil.getClasses(packageName);
        //获取类注解
        findClassExistAnnotation(classes);
        //依赖注入
        inject();
        //service事务代理
        serviceInject();

        return  beans;
    }

    /**
     * 将类注解为 KevinComponent KevinService KevinRepository 的类加入到bean
     * @param classes
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    public static Map<Class<?>, Object> findClassExistAnnotation(List<Class<?>> classes) throws IllegalAccessException, InstantiationException {

        for(Class<?> classInfo:classes){
            if(classInfo.isAnnotationPresent(KevinComponent.class)) {

                //此处还需要优化
                Class<?> interfaces[] = classInfo.getInterfaces();
                Class<?> intetmp = null;
                for (Class<?> inte : interfaces) {
                    intetmp = inte;
                }
                if(intetmp!=null){
                    beans.put(intetmp, classInfo.newInstance());
                }else{
                    beans.put(classInfo, classInfo.newInstance());
                }


            }else if(classInfo.isAnnotationPresent(KevinService.class)) {

                Class<?> interfaces[] = classInfo.getInterfaces();
                Class<?> intetmp = null;
                for (Class<?> inte : interfaces) {
                    intetmp = inte;
                }
                if(intetmp!=null){
                    beans.put(intetmp, classInfo.newInstance());
                }else{
                    beans.put(classInfo, classInfo.newInstance());
                }
            }else if(classInfo.isAnnotationPresent(KevinRepository.class)) {
                Class<?> interfaces[] = classInfo.getInterfaces();
                Class<?> intetmp = null;
                for (Class<?> inte : interfaces) {
                    intetmp = inte;
                }
                if(intetmp!=null){
                    beans.put(intetmp, classInfo.newInstance());
                }else{
                    beans.put(classInfo, classInfo.newInstance());
                }
            }
        }
        return beans;

    }


    /**
     * IOC 自动注入
     */
    public static void inject() {

        try {
            for (Map.Entry<Class<?>, Object> entry : beans.entrySet()) {
                Class<?> clazz = entry.getKey();
                Object obj = entry.getValue();
                Field[] fields = obj.getClass().getDeclaredFields();
                for (Field field : fields) {
                    if (field.isAnnotationPresent(KevinAutowired.class)) {
                        Class<?> fieldClazz = field.getType();
                        field.setAccessible(true);
                        Object fieldObj = beans.get(fieldClazz);
                        field.set(obj, fieldObj);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 针对service层处理 ，将service层中标注了KevinTransactional注解的类，重新使用代理工厂进行重新复制bean
     * 此方法还需要优化  目前类似事务注解指定在了service类上
     */
    public static void serviceInject() {

        try {
            for (Map.Entry<Class<?>, Object> entry : beans.entrySet()) {
                Class<?> clazz = entry.getKey();
                Object obj = entry.getValue();

                if(obj.getClass().isAnnotationPresent(KevinService.class)){
                    Method[] methods = obj.getClass().getMethods();
                    boolean trans = false;
                    for (Method method : methods) {
                        if(method.isAnnotationPresent(KevinTransactional.class)){
                            trans = true;
                        }
                    }
                    if(trans){
                        ProxyFactory proxyFactory = (ProxyFactory) beans.get(ProxyFactory.class);
                        Object jdkProxy = proxyFactory.getJdkProxy(obj);
                        beans.put(clazz,jdkProxy);
                    }
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
